package com.itheima.reggie.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itheima.reggie.common.R;
import com.itheima.reggie.dto.DishDto;
import com.itheima.reggie.entity.BaseEntity;
import com.itheima.reggie.entity.Category;
import com.itheima.reggie.entity.Dish;
import com.itheima.reggie.entity.DishFlavor;
import com.itheima.reggie.mapper.DishMapper;
import com.itheima.reggie.service.CategoryService;
import com.itheima.reggie.service.DishFlavorService;
import com.itheima.reggie.service.DishService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author Xiao
 * @date 2021/9/25
 */
@Service
@Slf4j
public class DishServiceImpl extends ServiceImpl<DishMapper, Dish> implements DishService {
    @Autowired
    private DishFlavorService dishFlavorService;
    @Autowired
    private CategoryService categoryService;
    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 根据categoryId查询菜品数量
     * @param categoryId
     * @return
     */
    @Override
    public int getCountByCategoryId(Long categoryId) {
        LambdaQueryWrapper<Dish> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Dish::getCategoryId,categoryId);
        return this.count(wrapper);
    }

    /**
     * 存储菜品
      * @param dishDto
     * @return
     */
    @Override
    @Transactional
    public boolean addDish(DishDto dishDto) {
        //存储菜品基本信息
        boolean result1 = this.save(dishDto);
        //存储菜品口味信息
        boolean result2 = dishFlavorService.saveFlavors(dishDto);
        //添加菜品后，清理所有分类下的缓存
        /*Set keys = redisTemplate.keys("dish_*"); //获取所有dish_开头的key
        redisTemplate.delete(keys);*/
        //添加菜品后，清理当前分类下的缓存
        String key = "dish_" + dishDto.getCategoryId() + "_1";
        redisTemplate.delete(key);
        return result1 && result2;
    }

    /**
     * 分页查询
     * @param page
     * @param pageSize
     * @param name
     * @return
     */
    @Override
    public Page<DishDto> getDishPage(Integer page, Integer pageSize, String name) {
        //分页查询Dish数据 --> Page<Dish>
        LambdaQueryWrapper<Dish> wrapper = new LambdaQueryWrapper<>();
        wrapper.like(StringUtils.isNotEmpty(name),Dish::getName,name);
        wrapper.orderByDesc(Dish::getUpdateTime);
        Page<Dish> dishPage = new Page<>(page, pageSize);
        this.page(dishPage, wrapper);
        // 创建Page<DishDto>对象，将Page<Dish>中数据拷贝到其中(records数据需要单独拷贝)
        Page<DishDto> dishDtoPage = new Page<>();
        BeanUtils.copyProperties(dishPage,dishDtoPage,"records");
        //拷贝records数据 --> 通过stream流
        List<Dish> dishPageRecords = dishPage.getRecords();
        List<DishDto> dishPageDtoRecords = dishPageRecords.stream().map(dish -> {
            //创建DishDto对象，使用BeanUtils将流上的Dish对象属性拷贝到DishDto中
            DishDto dishDto = new DishDto();
            BeanUtils.copyProperties(dish,dishDto);
            //通过Dish对象获取categoryId，再获取对应的Category对象
            Long categoryId = dish.getCategoryId();
            Category category = categoryService.getById(categoryId);
            //如果Category对象不为null，将categoryName取出来，设置为DishDto对象的属性值
            if (category != null) {
                String categoryName = category.getName();
                dishDto.setCategoryName(categoryName);
            }
            //返回DishDto对象
            return dishDto;
            //通过Collectors.toList()将所有复值后的DishDto对象放入集合中
        }).collect(Collectors.toList());
        //设置Page<DishDto>对象的records属性 --> 拷贝完成
        dishDtoPage.setRecords(dishPageDtoRecords);
        // 将categoryName属性封装到DishDto元素中
        return dishDtoPage;
    }

    /**
     * 根据id查询
     * @param id
     * @return
     */
    @Override
    public DishDto queryDishById(Long id) {
        Dish dish = this.getById(id);
        List<DishFlavor> flavors = dishFlavorService.queryFlavorsByDishId(id);
        DishDto dishDto = new DishDto();
        BeanUtils.copyProperties(dish,dishDto,"flavors");
        dishDto.setFlavors(flavors);
        //修改菜品时，清理当前分类下的缓存
        String key = "dish_" + dish.getCategoryId() + "_1";
        redisTemplate.delete(key);
        return dishDto;
    }

    /**
     * 修改菜品
     * @param dishDto
     * @return
     */
    @Override
    @Transactional
    public boolean editDish(DishDto dishDto) {
        //修改菜品基本信息
        boolean result1 = this.updateById(dishDto);
        List<DishFlavor> flavors = dishDto.getFlavors();
        //清除当前菜品修改前对应的口味数据
        boolean result2 = dishFlavorService.removeFlavors(dishDto.getId());
        //存储当前菜品修改后对应的口味数据
        boolean result3 = dishFlavorService.saveFlavors(dishDto);
        //修改菜品后，清理当前分类下的缓存
        String key = "dish_" + dishDto.getCategoryId() + "_1";
        redisTemplate.delete(key);
        return result1 && result2 && result3;
    }

    /**
     * (批量)修改状态
     * @param status
     * @param ids
     * @return
     */
    @Override
    public boolean dishStatusByStatus(Integer status, List<Long> ids) {
        List<Dish> dishes = this.listByIds(ids);
        for (Dish dish : dishes) {
            dish.setStatus(status);
        }
        return this.updateBatchById(dishes);
    }

    /**
     * (批量)删除
     * @param ids
     * @return
     */
    @Override
    @Transactional
    public boolean deleteDish(List<Long> ids) {
        List<Dish> dishes = this.listByIds(ids);
        for (Dish dish : dishes) {
            if (dish.getStatus() == 1) {
                return false;
            }
        }
        dishFlavorService.removeFlavorsByDishIds(ids);
        return this.removeByIds(ids);
    }

    /**
     * 根据分类id或菜品name属性查询
     * @param dish
     * @return
     */
    @Override
    public List<DishDto> queryDishList(Dish dish) {
        List<DishDto> dishDtos;
        //动态构造key
        String key = "dish_" + dish.getCategoryId() + "_" + dish.getStatus();
        //从redis中获取缓存数据
        dishDtos = (List<DishDto>) redisTemplate.opsForValue().get(key);
        //如果redis中有缓存数据，直接返回，无需查询数据库
        if (dishDtos != null) {
            return dishDtos;
        }
        //如果redis中没有缓存数据，查询数据库获取数据，并缓存到redis，设置过期时间
        LambdaQueryWrapper<Dish> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Dish::getStatus, 1);
        wrapper.eq(dish.getCategoryId() != null, Dish::getCategoryId, dish.getCategoryId());
        wrapper.like(dish.getName() != null, Dish::getName, dish.getName());
        wrapper.orderByAsc(Dish::getSort).orderByDesc(BaseEntity::getUpdateTime);
        List<Dish> dishes = this.list(wrapper);
        dishDtos = dishes.stream().map(item -> {
            DishDto dishDto = new DishDto();
            BeanUtils.copyProperties(item, dishDto);
            Category category = categoryService.getById(item.getCategoryId());
            if (category != null) {
                dishDto.setCategoryName(category.getName());
            }
            LambdaQueryWrapper<DishFlavor> wrapper1 = new LambdaQueryWrapper<>();
            wrapper1.eq(DishFlavor::getDishId, item.getId());
            List<DishFlavor> flavors = dishFlavorService.list(wrapper1);
            dishDto.setFlavors(flavors);
            return dishDto;
        }).collect(Collectors.toList());
        redisTemplate.opsForValue().set(key, dishDtos, 60L, TimeUnit.MINUTES);
        return dishDtos;
    }
}
